/*
 * @Author: lixu lixu@puchigames.com
 * @Date: 2025-09-18 11:30:00
 * @LastEditors: lixu lixu@puchigames.com
 * @LastEditTime: 2025-09-18 11:30:00
 * @FilePath: /go-helper/ixLog/sanitizer.go
 * @Description: 日志脱敏功能实现，支持敏感信息自动脱敏处理
 */

package ixLog

import (
	"fmt"
	"regexp"
	"strings"
)

// Sanitizer 脱敏器
type Sanitizer struct {
	fields   map[string]bool
	patterns []*regexp.Regexp
}

// NewSanitizer 创建脱敏器
func NewSanitizer(fields []string, patterns []string) *Sanitizer {
	sanitizer := &Sanitizer{
		fields: make(map[string]bool),
	}

	// 设置需要脱敏的字段
	for _, field := range fields {
		sanitizer.fields[strings.ToLower(field)] = true
	}

	// 编译正则表达式
	for _, pattern := range patterns {
		if regex, err := regexp.Compile(pattern); err == nil {
			sanitizer.patterns = append(sanitizer.patterns, regex)
		}
	}

	return sanitizer
}

// Sanitize 脱敏处理
func (s *Sanitizer) Sanitize(entry *LogEntry) {
	// 脱敏消息内容
	entry.Message = s.sanitizeString(entry.Message)

	// 脱敏字段
	for key, value := range entry.Fields {
		if s.shouldSanitizeField(key) {
			entry.Fields[key] = s.sanitizeValue(value)
		} else if str, ok := value.(string); ok {
			entry.Fields[key] = s.sanitizeString(str)
		}
	}

	// 脱敏错误信息
	if entry.Error != nil {
		errorMsg := entry.Error.Error()
		sanitizedMsg := s.sanitizeString(errorMsg)
		if sanitizedMsg != errorMsg {
			entry.Error = fmt.Errorf("%s", sanitizedMsg)
		}
	}
}

// shouldSanitizeField 检查字段是否需要脱敏
func (s *Sanitizer) shouldSanitizeField(field string) bool {
	return s.fields[strings.ToLower(field)]
}

// sanitizeValue 脱敏值
func (s *Sanitizer) sanitizeValue(value interface{}) interface{} {
	switch v := value.(type) {
	case string:
		return s.maskString(v)
	case []byte:
		return s.maskString(string(v))
	default:
		str := fmt.Sprintf("%v", v)
		return s.maskString(str)
	}
}

// sanitizeString 脱敏字符串
func (s *Sanitizer) sanitizeString(text string) string {
	result := text

	// 应用正则表达式脱敏
	for _, pattern := range s.patterns {
		result = pattern.ReplaceAllStringFunc(result, s.maskMatch)
	}

	return result
}

// maskString 完全遮蔽字符串
func (s *Sanitizer) maskString(text string) string {
	if len(text) == 0 {
		return text
	}

	if len(text) <= 2 {
		return "**"
	}

	if len(text) <= 4 {
		return text[:1] + "**" + text[len(text)-1:]
	}

	// 保留前后各2个字符
	return text[:2] + strings.Repeat("*", len(text)-4) + text[len(text)-2:]
}

// maskMatch 遮蔽匹配的内容
func (s *Sanitizer) maskMatch(match string) string {
	if len(match) <= 4 {
		return strings.Repeat("*", len(match))
	}

	// 保留前后各1个字符
	return match[:1] + strings.Repeat("*", len(match)-2) + match[len(match)-1:]
}

// 预定义脱敏规则
var (
	// 手机号脱敏：保留前3位和后4位
	PhonePattern = `\b1[3-9]\d{9}\b`

	// 邮箱脱敏：保留用户名首字符和域名
	EmailPattern = `\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b`

	// 身份证号脱敏：保留前6位和后4位
	IDCardPattern = `\b\d{15}|\d{18}\b`

	// 银行卡号脱敏：保留前4位和后4位
	BankCardPattern = `\b\d{16,19}\b`

	// IP地址脱敏：保留第一段
	IPPattern = `\b(?:\d{1,3}\.){3}\d{1,3}\b`

	// URL脱敏：保留协议和域名
	URLPattern = `https?://[^\s/$.?#].[^\s]*`
)

// DefaultSanitizePatterns 默认脱敏模式
func DefaultSanitizePatterns() []string {
	return []string{
		PhonePattern,
		EmailPattern,
		IDCardPattern,
		BankCardPattern,
	}
}

// DefaultSanitizeFields 默认脱敏字段
func DefaultSanitizeFields() []string {
	return []string{
		"password", "passwd", "pwd",
		"token", "access_token", "refresh_token",
		"secret", "secret_key", "api_secret",
		"key", "private_key", "public_key",
		"auth", "authorization",
		"cookie", "session",
		"credit_card", "card_number",
		"ssn", "social_security",
	}
}

// CustomSanitizeRule 自定义脱敏规则
type CustomSanitizeRule struct {
	Name        string
	Pattern     *regexp.Regexp
	Replacement func(string) string
}

// AdvancedSanitizer 高级脱敏器
type AdvancedSanitizer struct {
	*Sanitizer
	customRules []CustomSanitizeRule
}

// NewAdvancedSanitizer 创建高级脱敏器
func NewAdvancedSanitizer(fields []string, patterns []string) *AdvancedSanitizer {
	return &AdvancedSanitizer{
		Sanitizer: NewSanitizer(fields, patterns),
	}
}

// AddCustomRule 添加自定义脱敏规则
func (as *AdvancedSanitizer) AddCustomRule(name, pattern string, replacement func(string) string) error {
	regex, err := regexp.Compile(pattern)
	if err != nil {
		return fmt.Errorf("编译正则表达式失败: %w", err)
	}

	rule := CustomSanitizeRule{
		Name:        name,
		Pattern:     regex,
		Replacement: replacement,
	}

	as.customRules = append(as.customRules, rule)
	return nil
}

// Sanitize 高级脱敏处理
func (as *AdvancedSanitizer) Sanitize(entry *LogEntry) {
	// 先执行基础脱敏
	as.Sanitizer.Sanitize(entry)

	// 执行自定义规则
	for _, rule := range as.customRules {
		entry.Message = rule.Pattern.ReplaceAllStringFunc(entry.Message, rule.Replacement)

		for key, value := range entry.Fields {
			if str, ok := value.(string); ok {
				entry.Fields[key] = rule.Pattern.ReplaceAllStringFunc(str, rule.Replacement)
			}
		}
	}
}

// 预定义脱敏函数
var (
	// MaskPhone 手机号脱敏
	MaskPhone = func(phone string) string {
		if len(phone) != 11 {
			return strings.Repeat("*", len(phone))
		}
		return phone[:3] + "****" + phone[7:]
	}

	// MaskEmail 邮箱脱敏
	MaskEmail = func(email string) string {
		parts := strings.Split(email, "@")
		if len(parts) != 2 {
			return strings.Repeat("*", len(email))
		}

		username := parts[0]
		domain := parts[1]

		if len(username) <= 2 {
			return strings.Repeat("*", len(username)) + "@" + domain
		}

		return username[:1] + strings.Repeat("*", len(username)-2) + username[len(username)-1:] + "@" + domain
	}

	// MaskIDCard 身份证脱敏
	MaskIDCard = func(idcard string) string {
		if len(idcard) == 15 {
			return idcard[:6] + "*****" + idcard[11:]
		} else if len(idcard) == 18 {
			return idcard[:6] + "********" + idcard[14:]
		}
		return strings.Repeat("*", len(idcard))
	}

	// MaskBankCard 银行卡脱敏
	MaskBankCard = func(cardNo string) string {
		if len(cardNo) < 8 {
			return strings.Repeat("*", len(cardNo))
		}
		return cardNo[:4] + strings.Repeat("*", len(cardNo)-8) + cardNo[len(cardNo)-4:]
	}
)
